/*
Copyright (C) 2008 raohmaru <http://www.raohmaru.com>

This file is part of Raohmaru AS3 Framework.

Raohmaru AS3 Framework is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Raohmaru AS3 Framework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Raohmaru AS3 Framework.  If not, see <http://www.gnu.org/licenses/>.
*/

package jp.raohmaru.media
{
import jp.raohmaru.events.YouTubeEvent;

import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;

/**
 * Esta clase representa una interficie para controlar y poner en escena un reproductor de vídeo basado en la API de YouTube versión 3.
 * @author raohmaru
 * @version 1.0
 * @see http://code.google.com/intl/es/apis/youtube/flash_api_reference.html
 * @example
<listing version="3.0">
// Specifically allow the chromless player .swf access to our .swf.
Security.allowDomain("http://www.youtube.com");
Security.allowDomain("http://s.ytimg.com/");

import jp.raohmaru.media.YouTubePlayer;
import jp.raohmaru.events.YouTubeEvent;

var yt :YouTubePlayer = new YouTubePlayer(YouTubePlayer.CHROME);
    yt.addEventListener(YouTubeEvent.READY, onReady);
    yt.init("UX1z2RizWB8");
addChild(yt);

function onReady(e :YouTubeEvent) :void
{
    yt.setSize(stage.stageWidth, stage.stageHeight);
}
</listing>
 */
public class YouTubePlayer extends Sprite
{
	private var _loader :Loader,
				_player :Object,
				_id :String,
				_state :Object,
				_type :String;
	
	/**
	 * Establece la versión de la API de YouTube a utilizar.
	 */
	public static var version :Number = 3;
	
	/**
	 * Define que el reproductor debe utilizar el aspecto predefinido incluyendo los controles de reproducción.
	 */
	public static const CHROME :String = "chrome";
	
	/**
	 * Define que el reproductor no deba tener ninguna apariencia, únicamente mostrar el recuadro del vídeo.
	 */
	public static const CHROMELESS :String = "chromeless";	
	
	/**
	 * Obtiene el tipo de reproductor utilizado: con controles de reproducción ("chrome") o sin apariencia ("chromeless").
	 * @default "chromeless"
	 */
	public function get type() :String
	{
		return _type;
	}
	
	/**
	 * Devuelve el último estado del reproductor.
	 * Los valores posibles son no iniciado (-1), finalizado (0), en reproducción (1), pausado (2), almacenamiento en búfer (3) y en cola de vídeos (5).
	 * @see jp.raohmaru.media.YouTubePlayerState 
	 */
	public function get state() :int
	{
		return int(_state);
	}
	
	/**
	 * Obtiene el identificador del vídeo en reproducción.
	 */
	public function get videoID() :String
	{
		return _id;
	}
	
	/**
	 * Define o obtiene el volumen actual del reproductor, un número entero comprendido entre 0 y 100.
	 * El valor actual del volumen siempre será devuelto aunque el reproductor esté silenciado.
	 */
	public function get volume() :Number
	{
		return _player.getVolume();
	}
	public function set volume(value :Number) : void
	{
		_player.setVolume(value);
	}
	
	/**
	 * Devuelve la duración en segundos del vídeo que se está reproduciendo actualmente.
	 * El valor devuelto será 0 hasta que se hayan cargado los metadatos del vídeo, lo que normalmente se produce justo después de que comience la reproducción del vídeo.
	 */
	public function get duration() :Number
	{
		return _player.getDuration();
	}
	
	/**
	 * Devuelve el tiempo transcurrido en segundos desde que se inició la reproducción del vídeo.
	 */
	public function get currentTime() :Number
	{
		return _player.getCurrentTime();
	}
	
	/**
	 * Obtiene una referencia a la API reproductor de YouTube.
	 */
	public function get player() :Object
	{
		return _player;
	}
	

	/**
	 * Crea un nuevo objeto YouTubePlayer, un Sprite que contiene una instancia de la API del reproductor de YouTube
	 * para añadir al escenario.
	 * @param type La apariencia que tendrá el reproductor.
	 */
	public function YouTubePlayer(type :String="chromeless")
	{
		_type = type;
	}
	
	/**
	 * Inicializa el reproductor, descargando la API de YouTube y distribuyendo un evento <code>YouTubeEvent.READY</code> cuando el reproductor está listo para interactuar.
	 * @param autoPlayID Identificador de un vídeo para reproducir automáticamente cuando el reproductor esté listo.
	 */
	public function init(autoPlayID :String=null) :void
	{		
		_id = autoPlayID;
		
		var url :String = "http://www.youtube.com/apiplayer?version="+version;
		if(_type == CHROME)
		{
			url = "http://www.youtube.com/v/";
			url += (_id != null) ? _id : "u1zgFlCw8Aw";
			url += "?version="+version;
		}
		
		_loader = new Loader();
		_loader.contentLoaderInfo.addEventListener(Event.INIT, playerHandler);
		_loader.load(new URLRequest(url));
	}
	
	/**
	 * Detiene la reproducción actual y cierra el flujo de datos, eliminando el vídeo en reproducción.
	 */
	public function close() :void
	{
		if(_player)
		{
			_player.stopVideo();
			_player.mute();
		}
		_id = null;
	}	
	
	/**
	 * Detiene la reproducción actual y destruye la instancia de la API de YouTube.
	 * El reproductor no puede ser utilizado. 
	 */
	public function destroy() :void
	{
		_loader.contentLoaderInfo.removeEventListener(Event.INIT, playerHandler);
		_loader.content.removeEventListener(YouTubeEvent.READY, playerHandler);
		_loader.content.removeEventListener(YouTubeEvent.ERROR, playerHandler);
		_loader.content.removeEventListener(YouTubeEvent.STATE_CHANGE, playerHandler);
		_loader.content.removeEventListener(YouTubeEvent.QUALITY_CHANGE, playerHandler);
		
		close();		
		_player.destroy();
		_player = null;
		
		removeChild(_loader);
		if(_loader.hasOwnProperty("unloadAndStop"))
			_loader["unloadAndStop"](true);
		else
			_loader.unload();
		_loader = null;
	}
	
	/**
	 * Carga y reproduce el vídeo especificado o reproduce el vídeo que se encuentra cargado.
	 * @param id Identificador del vídeo a reproducir.
	 */
	public function play(id :String=null) :void
	{
		if(id != null && id != _id)
		{
			_player.loadVideoById(id, 0, "default");
			_id = id;
		}
		else
			_player.playVideo();
		
		_player.unMute();
	}
	
	/**
	 * Pausa el vídeo que se está reproduciendo en este momento.
	 */
	public function pause() :void
	{
		_player.pauseVideo();
	}
	
	/**
	 * Desplaza la reproducción hasta el momento especificado del vídeo en segundos.
	 * @param seconds Segundo que se buscará en el vídeo.
	 */
	public function seekTo(seconds: Number) :void
	{
		_player.seekTo(seconds, true);
	}
	
	/**
	 * Define el tamaño en píxeles del reproductor.
	 * Se debe utilizar este método en lugar de establecer las propiedades <code>width</code> y <code>height</code> de la instancia de YouTubePlayer.
	 * @param width Ancho en píxeles del reproductor.
	 * @param height Alto en píxeles del reproductor.
	 */
	public function setSize(width:Number, height:Number) :void
	{
		_player.setSize(width, height);
	}
	
	
	
	private function playerHandler(e :Event):void
	{
		if(e.type == Event.INIT)
		{
			_loader.contentLoaderInfo.removeEventListener(Event.INIT, playerHandler);
			addChild(_loader);
			
			_loader.content.addEventListener(YouTubeEvent.READY, playerHandler);
			_loader.content.addEventListener(YouTubeEvent.ERROR, playerHandler);
			_loader.content.addEventListener(YouTubeEvent.STATE_CHANGE, playerHandler);
			_loader.content.addEventListener(YouTubeEvent.QUALITY_CHANGE, playerHandler);
		}
		
		else if(e.type == YouTubeEvent.READY)
		{
			_player = _loader.content;
			
			if(_id == null)
				close();
			else
			{
				var id :String = _id;
				_id = null;
				play(id);
			}
			
			_loader.content.removeEventListener(YouTubeEvent.READY, playerHandler);
			dispatchEvent(new YouTubeEvent(YouTubeEvent.READY));
		}
		
		else if(e.type == YouTubeEvent.ERROR)
		{
			//trace("player error:", Object(e).data);
			dispatchEvent(new YouTubeEvent(YouTubeEvent.ERROR, Object(e).data));
		}
		
		else if(e.type == YouTubeEvent.STATE_CHANGE)
		{
			//trace("player state:", Object(e).data);
			_state = Object(e).data;
			dispatchEvent(new YouTubeEvent(YouTubeEvent.STATE_CHANGE, Object(e).data));
		}
		
		else if(e.type == YouTubeEvent.QUALITY_CHANGE)
		{
			//trace("video quality:", Object(e).data);
			dispatchEvent(new YouTubeEvent(YouTubeEvent.QUALITY_CHANGE, Object(e).data));
		}
	}
}
}